"""
Authentication middleware for API key validation
"""
import logging
from typing import Optional, List
from fastapi import Request, HTTPException
from starlette.middleware.base import BaseHTTPMiddleware

logger = logging.getLogger(__name__)


class AuthenticationMiddleware(BaseHTTPMiddleware):
    """
    Authentication middleware for API key validation
    """
    
    def __init__(
        self,
        app,
        enabled: bool = False,
        api_key: Optional[str] = None,
        api_key_header: str = "X-API-Key",
        skip_paths: List[str] = None,
        public_paths: List[str] = None
    ):
        super().__init__(app)
        self.enabled = enabled
        self.api_key = api_key
        self.api_key_header = api_key_header.lower()  # Store lowercase for case-insensitive comparison
        
        # Paths that skip authentication entirely (docs, health checks, etc.)
        self.skip_paths = skip_paths or [
            "/docs", "/redoc", "/openapi.json", "/health", "/", "/favicon.ico"
        ]
        
        # Public paths that don't require authentication even when auth is enabled
        self.public_paths = public_paths or []
    
    async def dispatch(self, request: Request, call_next):
        # Skip if authentication is disabled
        if not self.enabled:
            return await call_next(request)
        
        # Skip certain paths entirely
        if any(request.url.path.startswith(path) for path in self.skip_paths):
            return await call_next(request)
        
        # Allow public paths even when auth is enabled
        if any(request.url.path.startswith(path) for path in self.public_paths):
            return await call_next(request)
        
        # Check authentication
        if not await self._is_authenticated(request):
            logger.warning(f"Unauthorized access attempt to {request.url.path} from {self._get_client_ip(request)}")
            
            raise HTTPException(
                status_code=401,
                detail={
                    "error": "Authentication required",
                    "message": f"Valid API key required in {self.api_key_header} header",
                    "type": "authentication_error"
                },
                headers={"WWW-Authenticate": f"ApiKey realm=\"API Key required in {self.api_key_header} header\""}
            )
        
        return await call_next(request)
    
    async def _is_authenticated(self, request: Request) -> bool:
        """
        Check if request is authenticated
        """
        if not self.api_key:
            logger.warning("Authentication enabled but no API key configured")
            return False
        
        # Get API key from headers (case-insensitive)
        request_api_key = None
        for header_name, header_value in request.headers.items():
            if header_name.lower() == self.api_key_header:
                request_api_key = header_value
                break
        
        if not request_api_key:
            logger.debug(f"No API key found in {self.api_key_header} header")
            return False
        
        # Validate API key
        if request_api_key != self.api_key:
            logger.warning(f"Invalid API key provided: {request_api_key[:8]}...")
            return False
        
        logger.debug(f"Valid API key provided for {request.url.path}")
        return True
    
    def _get_client_ip(self, request: Request) -> str:
        """Get client IP address"""
        forwarded_for = request.headers.get("x-forwarded-for")
        if forwarded_for:
            return forwarded_for.split(",")[0].strip()
        
        real_ip = request.headers.get("x-real-ip")
        if real_ip:
            return real_ip.strip()
        
        if request.client and request.client.host:
            return request.client.host
        
        return "unknown"


class SecurityHeadersMiddleware(BaseHTTPMiddleware):
    """
    Middleware to add security headers to responses
    """
    
    def __init__(self, app, add_security_headers: bool = True):
        super().__init__(app)
        self.add_security_headers = add_security_headers
    
    async def dispatch(self, request: Request, call_next):
        response = await call_next(request)
        
        if self.add_security_headers:
            # Add security headers
            response.headers["X-Content-Type-Options"] = "nosniff"
            response.headers["X-Frame-Options"] = "DENY"
            response.headers["X-XSS-Protection"] = "1; mode=block"
            response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
            response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
            response.headers["Pragma"] = "no-cache"
            response.headers["Expires"] = "0"
            
            # Add Content Security Policy for API responses
            if "application/json" in response.headers.get("content-type", ""):
                response.headers["Content-Security-Policy"] = "default-src 'none'"
        
        return response


def authentication_middleware(
    enabled: bool = False,
    api_key: Optional[str] = None,
    api_key_header: str = "X-API-Key",
    skip_paths: List[str] = None,
    public_paths: List[str] = None
):
    """Factory function to create authentication middleware"""
    def create_middleware(app):
        return AuthenticationMiddleware(
            app=app,
            enabled=enabled,
            api_key=api_key,
            api_key_header=api_key_header,
            skip_paths=skip_paths,
            public_paths=public_paths
        )
    return create_middleware


def security_headers_middleware(add_security_headers: bool = True):
    """Factory function to create security headers middleware"""
    def create_middleware(app):
        return SecurityHeadersMiddleware(app, add_security_headers=add_security_headers)
    return create_middleware